package com.xayy.mgt.service.impl;

import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.base.utils.StringUtil;
import cn.kawins.mybatis.base.BaseServiceImpl;
import com.xayy.core.constant.ConfigCalPath;
import com.xayy.core.utils.MercatorAndWgs84;
import com.xayy.mgt.enums.SateJGTEnum;
import com.xayy.mgt.enums.SateRateEnum;
import com.xayy.mgt.mapper.GenerateAssessDataMapper;
import com.xayy.mgt.model.vo.SateRateAndCacheVo;
import com.xayy.mgt.model.xinwangmodel.AssessData;
import com.xayy.mgt.model.xinwangmodel.HealthEntity;
import com.xayy.mgt.model.xinwangmodel.SateLinkData;
import com.xayy.mgt.model.xinwangmodel.SateListData;
import com.xayy.mgt.service.GenerateAssessDataService;
import com.xayy.mgt.service.GenerateTheoryDataAsyncService;
import com.xayy.mgt.service.GenerateTheoryDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 生成评估数据
 * @author plq
 */
@Service
@Slf4j
public class GenerateAssessDataServiceImpl extends BaseServiceImpl<AssessData> implements GenerateAssessDataService {

    @Autowired
    private GenerateTheoryDataService generateTheoryDataService;

    @Autowired
    private GenerateTheoryDataAsyncService gg;

    @Autowired
    private GenerateAssessDataMapper generateAssessDataMapper;

    @Autowired
    private ConfigCalPath configCalPath;

    @SuppressWarnings("unchecked")
    @Override
    public CheckResult<Object> generateAssessData(String region, Long nodeId, Date time) {
        boolean b1 = generateTheoryDataService.checkNodeNumber(nodeId);
        if(!b1){
            return CheckResult.success(new ArrayList<>());
        }
        if("2".equals(region) ||  "3".equals(region)){
            return getDMZData(region,nodeId,time);
        }
        if(time == null){
            return CheckResult.success(new ArrayList<>());
        }
        /*获取卫星列表*/
        SateListData sateListData = generateTheoryDataService.getSatelliteList();
        if(sateListData == null){
            OutInterfaceServiceImpl.addXZLogs("获取第三方卫星列表失败");
            return CheckResult.fail("获取卫星列表失败");
        }
        /*获取卫星编号对应的数据对象*/
        List<SateListData.Records> sateList = sateListData.getResult().getRecords();
        sateList.sort((a,b) ->{
            int aInt = Integer.parseInt(a.getNumber().replaceAll("[a-zA-Z]", ""));
            int bInt = Integer.parseInt(b.getNumber().replaceAll("[a-zA-Z]", ""));
            return aInt - bInt;
        });
        OutInterfaceServiceImpl.addXZLogs("获取第三方卫星列表数量："+sateList.size());
        /*获取卫星拓扑图*/
        List<SateLinkData> records = (List<SateLinkData>)generateTheoryDataService.getTheoryData(region,nodeId).body().getData();
        OutInterfaceServiceImpl.addXZLogs("获取第三方卫星拓扑图列表数量："+records.size());
        /*计算卫星激光头连接情况*/
        /*根据卫星code获取6个轨道面的卫星。*/
        Map<Integer,List<SateLinkData>> gdmMap = new LinkedHashMap<>(6);
        for(int j = 1 ; j<= 6 ; j++){
            /*同一轨道面最小编号卫星*/
            int minNum = (j-1)*10+1;
            /*同一轨道面最大编号卫星*/
            int maxNum = (j-1)*10+10;
            List<SateLinkData> gdmList = new ArrayList<>();
            for (SateLinkData record : records) {
                int aInt = Integer.parseInt(record.getSatelliteCode1().replaceAll("[a-zA-Z]", ""));
                if(aInt >= minNum && aInt <= maxNum){
                    gdmList.add(record);
                }
            }
            gdmMap.put(j,gdmList);
        }
        List<SateLinkData> linkDataList = new ArrayList<>();
        OutInterfaceServiceImpl.addXZLogs("计算轨道面卫星连接数据");
        /*获取每个轨道面上下相连卫星*/
        gdmMap.forEach((k,v) ->{
            /*获取同一轨道面卫星，去重*/
            List<String> collect1 = v.stream().map(SateLinkData::getSatelliteCode1).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            /*计算同一轨道面连接情况*/
            collect1.forEach(item ->{
                /*获取相连接的两个卫星*/
                List<SateLinkData> collect = v.stream().filter(f -> f.getSatelliteCode1().equals(item) && collect1.contains(f.getSatelliteCode2())).collect(Collectors.toList());
                /*判断相连的两个卫星的编号大小确定激光头的编号连接*/
                collect.forEach(col ->{
                    SateLinkData sateLinkData = SateLinkData.builder().satelliteCode1(col.getSatelliteCode1()).satelliteCode2(col.getSatelliteCode2()).build();
                    /*获取卫星1名称,并且给1卫星添加xyz坐标*/
                    SateListData.Records records2 = sateList.stream().filter(f -> f.getNumber().equals(col.getSatelliteCode1())).collect(Collectors.toList()).stream().findFirst().orElse(new SateListData.Records());
                    sateLinkData.setSatelliteName1(records2.getName());
                    double[] doubles = removeAndToDouble(records2.getX(), records2.getY());
                    sateLinkData.setSatellite1x(doubles[0]);
                    sateLinkData.setSatellite1y(doubles[1]);
                    /*获取卫星2名称*/
                    SateListData.Records collect3 = sateList.stream().filter(f -> f.getNumber().equals(col.getSatelliteCode2())).collect(Collectors.toList()).stream().findFirst().orElse(new SateListData.Records());
                    sateLinkData.setSatelliteName2(collect3.getName());
                    double[] doubles2 = removeAndToDouble(collect3.getX(), collect3.getY());
                    sateLinkData.setSatellite2x(doubles2[0]);
                    sateLinkData.setSatellite2y(doubles2[1]);
                    /*编号小的用2，大的用1*/
                    if(removeEN(col.getSatelliteCode1()) < removeEN(col.getSatelliteCode2())){
                        sateLinkData.setSatellite1JGTCode(2);
                        sateLinkData.setSatellite2JGTCode(1);
                    }else{
                        sateLinkData.setSatellite1JGTCode(1);
                        sateLinkData.setSatellite2JGTCode(2);
                    }
                    /*如果是第一个和最后一个，大的用2，小的用1*/
                    String firstSate = collect1.get(0);
                    String lastSate = collect1.get(collect1.size()-1);
                    if(firstSate.equals(col.getSatelliteCode1()) && lastSate.equals(col.getSatelliteCode2())){
                        sateLinkData.setSatellite1JGTCode(1);
                        sateLinkData.setSatellite2JGTCode(2);
                    }
                    /*如果是最后一个和第一个，大的用2，小的用1*/
                    if(lastSate.equals(col.getSatelliteCode1()) && firstSate.equals(col.getSatelliteCode2())){
                        sateLinkData.setSatellite1JGTCode(2);
                        sateLinkData.setSatellite2JGTCode(1);
                    }
                    sateLinkData.setSateRateTheoryValue(col.getSateRateTheoryValue());
                    linkDataList.add(sateLinkData);
                });
            });
        });
        /*计算不同轨道面每个卫星相连*/
        records.forEach(a -> {
            /*判断如果是同一轨道面则跳过*/
            long count = linkDataList.stream().filter(f -> f.getSatelliteCode1().equals(a.getSatelliteCode1()) && f.getSatelliteCode2().equals(a.getSatelliteCode2())).count();
            if(count > 0){
                return;
            }
            /*获取第一个卫星的x*/
            SateListData.Records oneSate = sateList.stream().filter(f -> f.getNumber().equals(a.getSatelliteCode1())).collect(Collectors.toList()).stream().findFirst().orElse(new SateListData.Records());
            /*获取第二个卫星的x*/
            SateListData.Records twoSate = sateList.stream().filter(f -> f.getNumber().equals(a.getSatelliteCode2())).collect(Collectors.toList()).stream().findFirst().orElse(new SateListData.Records());
            /*判断坐标*/
            double[] oneDoubles = removeAndToDouble(oneSate.getX(), oneSate.getY());
            double[] twoDoubles = removeAndToDouble(twoSate.getX(), twoSate.getY());
            SateLinkData sateLinkData = SateLinkData.builder()
                    .satelliteCode1(a.getSatelliteCode1())
                    .satelliteCode2(a.getSatelliteCode2())
                    .satelliteName1(oneSate.getName())
                    .satelliteName2(twoSate.getName())
                    .satellite1x(oneDoubles[0])
                    .satellite1y(oneDoubles[1])
                    .satellite2x(twoDoubles[0])
                    .satellite2y(twoDoubles[1])
                    .build();
            /*
            根据经度计算卫星左右激光头相连方向
            */
            if((oneDoubles[0] >= 0D && twoDoubles[0] >= 0D) || (oneDoubles[0] <= 0D  && twoDoubles[0] <= 0D)){
                if(oneDoubles[0] > twoDoubles[0]){
                    sateLinkData.setSatellite1JGTCode(3);
                    sateLinkData.setSatellite2JGTCode(4);
                }else{
                    sateLinkData.setSatellite1JGTCode(4);
                    sateLinkData.setSatellite2JGTCode(3);
                }
            }else {
                if(Math.abs(oneDoubles[0])+ Math.abs(twoDoubles[0]) > 180D){
                    if(oneDoubles[0] > twoDoubles[0]){
                        sateLinkData.setSatellite1JGTCode(4);
                        sateLinkData.setSatellite2JGTCode(3);
                    }else{
                        sateLinkData.setSatellite1JGTCode(3);
                        sateLinkData.setSatellite2JGTCode(4);
                    }
                }else{
                    if(oneDoubles[0] > twoDoubles[0]){
                        sateLinkData.setSatellite1JGTCode(3);
                        sateLinkData.setSatellite2JGTCode(4);
                    }else{
                        sateLinkData.setSatellite1JGTCode(4);
                        sateLinkData.setSatellite2JGTCode(3);
                    }
                }
            }
            sateLinkData.setSateRateTheoryValue(a.getSateRateTheoryValue());
            linkDataList.add(sateLinkData);
        });
        linkDataList.sort((a,b) ->{
            int aInt = Integer.parseInt(a.getSatelliteCode1().replaceAll("[a-zA-Z]", ""));
            int bInt = Integer.parseInt(b.getSatelliteCode1().replaceAll("[a-zA-Z]", ""));
            return aInt - bInt;
        });
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.MINUTE,-5);
        Date startTime = calendar.getTime();
        /*获取所有卫星激光头速率*/
        List<String> sateCodeList = sateList.stream().map(m -> {
            int aInt = Integer.parseInt(m.getName().replaceAll("[a-zA-Z]", ""));
            return "polar "+aInt;
        }).collect(Collectors.toList());

        /*调用第三方接口获取遥测数据，获取每个卫星激光头速率*/
        //TODO
        List<Map<String,Object>> reDataList =  generateAssessDataMapper.selectAllSateRateList(sateCodeList,startTime,time);
        if(CollUtil.isEmpty(reDataList)){
            OutInterfaceServiceImpl.addXZLogs("获取激光头相关遥测数据失败");
            return CheckResult.fail("未获取到遥测数据");
        }
        OutInterfaceServiceImpl.addXZLogs("获取激光头相关遥测数据："+configCalPath.getTelAndFaultUrl()+"/health-xw-back-moni/v1.0/imitate/getTelemetryData 数据："+sateCodeList+" "+startTime+" "+time);
        OutInterfaceServiceImpl.addXZLogs("获取激光头相关遥测数据数量："+reDataList.size());
        OutInterfaceServiceImpl.addXZLogs("激光头速率计算");
        /*处理速率问题*/
        linkDataList.forEach(f ->{
            /*默认速率为0*/
            f.setSatellite1Rate(0D);
            f.setSatellite2Rate(0D);
            /*查询卫星1每个激光头的速率*/
            if(StringUtil.isNotBlank(f.getSatelliteCode1()) && StringUtil.isNotBlank(f.getSatelliteName1())){
                String sateCode = "polar "+ Integer.parseInt(f.getSatelliteName1().replaceAll("[a-zA-Z]", ""));
                Map<String, Object> satelliteCode = reDataList.stream().filter(rateData -> sateCode.equals(rateData.get("satelliteCode"))).collect(Collectors.toList()).stream().findFirst().orElse(null);
                if(satelliteCode != null){
                    String s = satelliteCode.get(SateJGTEnum.getCode(f.getSatellite1JGTCode())).toString();
                    Double rate = SateRateEnum.getRate(Integer.parseInt(s));
                    /*如果状态为1.则设置速率为激光头速率*/
                    String status = satelliteCode.get(SateJGTEnum.getStatusCode(f.getSatellite1JGTCode())).toString();
                    if("1".equals(status)){
                        f.setSatellite1Rate(rate);
                    }
                }
            }
            /*查询卫星2每个激光头的速率*/
            if(StringUtil.isNotBlank(f.getSatelliteCode2()) && StringUtil.isNotBlank(f.getSatelliteName2())){
                int bInt = Integer.parseInt(f.getSatelliteName2().replaceAll("[a-zA-Z]", ""));
                String sateCode2 = "polar "+bInt;
                Map<String, Object> reData2 = reDataList.stream().filter(rateData -> sateCode2.equals(rateData.get("satelliteCode"))).collect(Collectors.toList()).stream().findFirst().orElse(null);
                if(reData2 != null){
                    String s = reData2.get(SateJGTEnum.getCode(f.getSatellite2JGTCode())).toString();
                    Double rate = SateRateEnum.getRate(Integer.parseInt(s));
                    /*如果状态为1.则设置速率为激光头速率*/
                    String status = reData2.get(SateJGTEnum.getStatusCode(f.getSatellite2JGTCode())).toString();
                    if("1".equals(status)){
                        f.setSatellite2Rate(rate);
                    }
                }
            }
            f.setSateRateRealityValue(f.getSatellite1Rate());
            if(f.getSatellite1Rate()> f.getSatellite2Rate()){
                f.setSateRateRealityValue(f.getSatellite2Rate());
            }
        });
        OutInterfaceServiceImpl.addXZLogs("激光头速率计算完成");
        return CheckResult.success(linkDataList);
    }

    /**
     * 获取地面站数据
     * @param region 区域
     * @return CheckResult
     */
    @SuppressWarnings("unchecked")
    private CheckResult<Object> getDMZData(String region,Long nodeId,Date endDate) {
        List<SateLinkData> list = (List<SateLinkData>)generateTheoryDataService.getTheoryData(region,nodeId).body().getData();
        /*获取实际遥测数据*/
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endDate);
        calendar.add(Calendar.MINUTE,-5);
        Date startTime = calendar.getTime();

        /*获取卫星列表*/
        SateListData sateListData = generateTheoryDataService.getSatelliteList();
        if(sateListData == null){
            return CheckResult.fail("获取卫星列表失败");
        }
        /*获取卫星编号对应的数据对象*/
        List<SateListData.Records> sateList = sateListData.getResult().getRecords();
        List<String> sateCodeList = sateList.stream().map(m -> {
            int aInt = Integer.parseInt(m.getName().replaceAll("[a-zA-Z]", ""));
            return "polar "+aInt;
        }).collect(Collectors.toList());
        /*获取遥测参数信息*/
        List<Map<String,Object>> reDataList =  generateAssessDataMapper.selectAllSateRateList(sateCodeList,startTime,endDate);
        if(CollUtil.isEmpty(reDataList)){
            return CheckResult.fail("未获取到遥测数据");
        }
        //TODO 远程获取
        list.forEach(item ->{
            String sateCode1;
            int bInt;
            if("2".equals(region)){
                bInt = Integer.parseInt(item.getSatelliteName1().replaceAll("[a-zA-Z]", ""));
            }else{
                bInt = Integer.parseInt(item.getSatelliteName2().replaceAll("[a-zA-Z]", ""));
            }
            sateCode1 = "polar "+bInt;
            Map<String, Object> reData2 = reDataList.stream().filter(rateData -> sateCode1.equals(rateData.get("satelliteCode"))).collect(Collectors.toList()).stream().findFirst().orElse(null);
            if(reData2 != null){
                String s = reData2.get(SateJGTEnum.getCode(5)).toString();
                Double rate = Double.parseDouble(s);
                /*如果状态为1.则设置速率为激光头速率*/
                String status = reData2.get(SateJGTEnum.getStatusCode(5)).toString();
                if("1".equals(status)){
                    item.setSateRateRealityValue(rate);
                }
            }
        });
        return CheckResult.success(list);

    }

    @SuppressWarnings("unchecked")
    @Override
    public CheckResult<Object> siteRateAndCache(Long nodeId,Date endDate) {
        boolean b1 = generateTheoryDataService.checkNodeNumber(nodeId);
        if(!b1){
            return CheckResult.success(new ArrayList<>());
        }
        /*获取卫星列表*/
        SateListData sateListData = generateTheoryDataService.getSatelliteList();
        if(sateListData == null){
            return CheckResult.fail("获取卫星列表失败");
        }
        /*获取卫星编号对应的数据对象*/
        List<SateListData.Records> sateList = sateListData.getResult().getRecords();
        sateList.sort((a,b) ->{
            int aInt = Integer.parseInt(a.getNumber().replaceAll("[a-zA-Z]", ""));
            int bInt = Integer.parseInt(b.getNumber().replaceAll("[a-zA-Z]", ""));
            return aInt - bInt;
        });
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endDate);
        calendar.add(Calendar.MINUTE,-5);
        Date startTime = calendar.getTime();
        /*获取卫星编号对应的数据对象*/
        List<String> sateCodeList = sateList.stream().map(m -> {
            int aInt = Integer.parseInt(m.getName().replaceAll("[a-zA-Z]", ""));
            return "polar "+aInt;
        }).collect(Collectors.toList());
        /*调用第三方接口获取遥测数据，获取每个卫星激光头速率*/
        //TODO
        List<Map<String,Object>> reDataList =  generateAssessDataMapper.selectAllSateRateList(sateCodeList,startTime,endDate);
        if(CollUtil.isEmpty(reDataList)){
            return CheckResult.fail("未获取到遥测数据");
        }
        /*处理数据*/
        List<SateRateAndCacheVo> list = new ArrayList<>();
        sateList.forEach(item ->{
            /*获取对应卫星*/
            int bInt = Integer.parseInt(item.getName().replaceAll("[a-zA-Z]", ""));
            String sateCode2 = "polar "+bInt;
            Map<String, Object> reData2 = reDataList.stream().filter(rateData -> sateCode2.equals(rateData.get("satelliteCode"))).collect(Collectors.toList()).stream().findFirst().orElse(null);
            double allRate = 0D;
            if(reData2 != null){
                String status1 = reData2.get(SateJGTEnum.getStatusCode(1)).toString();
                if("1".equals(status1)){
                    String rate = reData2.get(SateJGTEnum.getCode(1)).toString();
                    if(StringUtil.isNotBlank(rate)){
                        allRate+= SateRateEnum.getRate(Integer.parseInt(rate));
                    }
                }
                String status2 = reData2.get(SateJGTEnum.getStatusCode(2)).toString();
                if("1".equals(status2)){
                    String rate = reData2.get(SateJGTEnum.getCode(2)).toString();
                    if(StringUtil.isNotBlank(rate)){
                        allRate+= SateRateEnum.getRate(Integer.parseInt(rate));
                    }
                }
                String status3 = reData2.get(SateJGTEnum.getStatusCode(3)).toString();
                if("1".equals(status3)){
                    String rate = reData2.get(SateJGTEnum.getCode(3)).toString();
                    if(StringUtil.isNotBlank(rate)){
                        allRate+= SateRateEnum.getRate(Integer.parseInt(rate));
                    }
                }
                String status4 = reData2.get(SateJGTEnum.getStatusCode(4)).toString();
                if("1".equals(status4)){
                    String rate = reData2.get(SateJGTEnum.getCode(4)).toString();
                    if(StringUtil.isNotBlank(rate)){
                        allRate+= SateRateEnum.getRate(Integer.parseInt(rate));
                    }
                }
            }
            SateRateAndCacheVo siteRateAndCacheVo = SateRateAndCacheVo.builder()
                    .sateRateTheoryValue(Double.parseDouble(String.valueOf(item.getTranPw())))
                    .sateCode(item.getNumber())
                    .sateName(item.getName())
                    .sateRateRealityValue(allRate)
                    .cacheTheoryValue(Double.parseDouble(String.valueOf(item.getBuffer())))
                    .cacheRealityValue(2000D)
                    .build();
            list.add(siteRateAndCacheVo);

        });
        /*排序*/
        list.sort((a,b) ->{
            int bInt = Integer.parseInt(b.getSateName().replaceAll("[a-zA-Z]", ""));
            int aInt = Integer.parseInt(a.getSateName().replaceAll("[a-zA-Z]", ""));
            return aInt - bInt;
        });
        return CheckResult.success(list);
    }

    @SuppressWarnings("unchecked")
    @Override
    public CheckResult<Object> healthAssess(HealthEntity healthEntity) {
        boolean b1 = generateTheoryDataService.checkNodeNumber(healthEntity.getNodeId());
        if(!b1){
            OutInterfaceServiceImpl.addXZLogs("星座校验：只支持60或108颗卫星");
            return CheckResult.fail("只支持60或108颗卫星");
        }
        OutInterfaceServiceImpl.addXZLogs("星座校验结果：true");
        /*获取token*/
        String adminToken = gg.getAdminToken().get("token").toString();
        if(adminToken == null){
            OutInterfaceServiceImpl.addXZLogs("获取第三方token：false");
            return CheckResult.fail("获取adminToken失败");
        }
        OutInterfaceServiceImpl.addXZLogs("获取第三方token："+adminToken);
        CheckResult<Object> objectCheckResult = generateAssessData("1", healthEntity.getNodeId(), healthEntity.getTime());
        if(objectCheckResult.ok()){
            /*异步健康评估*/
            List<SateLinkData> data = (List<SateLinkData>)objectCheckResult.getData();
            if(data == null || data.isEmpty()){
                OutInterfaceServiceImpl.addXZLogs("暂无遥测数据");
                return CheckResult.fail("暂无遥测数据");
            }
            OutInterfaceServiceImpl.addXZLogs("请求数据评估");
            gg.healthAsyncAssess(healthEntity,adminToken,data);
            return CheckResult.success("请求成功，正在评估中");
        }
        return CheckResult.fail(objectCheckResult.getCheckMsg());
    }

    /**
     * 移除掉英文
     */
    private Integer removeEN(String nodeStr){
        return Integer.parseInt(nodeStr.replaceAll("[a-zA-Z]", ""));
    }
    /**
     * 原始坐标移除中括号并且转Double,墨卡托转经纬度返回
     */
    private double[] removeAndToDouble(String x,String y){
        String xReplace = x.replace("[", "").replace("]", "");
        String yReplace = y.replace("[", "").replace("]", "");
        return MercatorAndWgs84.mercatorToWgs84(Double.parseDouble(xReplace), Double.parseDouble(yReplace));
    }


}
